﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.IO;
using UCL;
using UCL.ADF;

namespace SoIM
{
    /// <summary>
    /// 2013-11-5 by sutroon
    /// </summary>
    public partial class frmServicesControl : Form
    {
        /// <summary>
        /// 接收到消息的处理事件
        /// </summary>
        public Action<string,string,int> MessageReceivedHandler { get; set; }

        Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>(); //用于保存所有通信客户端的Socket

        string clientName = null; //创建访问客户端的名字  
        IPAddress clientIP; //访问客户端的IP  
        int clientPort; //访问客户端的端口号  
        string strSRecMsg = null;

        Thread threadWatch = null; //负责监听客户端的线程  
        Socket socketWatch = null; //负责监听客户端的套接字  
        Socket socConnection = null;  //创建一个负责和客户端通信的套接字   

        string port = "6066";
        string ip;

        AppDataHelper adh;
        public frmServicesControl()
        {
            InitializeComponent();
            //关闭对文本框的非法线程操作检查  
            RichTextBox.CheckForIllegalCrossThreadCalls = false;
            TextBox.CheckForIllegalCrossThreadCalls = false;
            adh = new AppDataHelper();
            ip = IPHelper.GetIPAddress();

            // 启动服务
            this.StartServer();
        }

        /// <summary>
        /// 开始启动服务器
        /// </summary>
        private void StartServer()
        {
            //定义一个套接字用于监听客户端发来的信息  包含3个参数(IP4寻址协议,流式连接,TCP协议)  
            socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //服务端发送信息 需要1个IP地址和端口号  
            IPAddress ipaddress = IPAddress.Parse(ip.Trim()); //获取文本框输入的IP地址  
            //将IP地址和端口号绑定到网络节点endpoint上   
            IPEndPoint endpoint = new IPEndPoint(ipaddress, int.Parse(port.Trim())); //获取文本框上输入的端口号  
            //监听绑定的网络节点  
            socketWatch.Bind(endpoint);
            //将套接字的监听队列长度限制为20  
            socketWatch.Listen(20);
            //创建一个监听线程   
            threadWatch = new Thread(WatchConnecting);
            //将窗体线程设置为与后台同步  
            threadWatch.IsBackground = true;
            //启动线程  
            threadWatch.Start();
        }

        /// <summary>
        /// 监听客户端发来的请求  
        /// </summary> 
        private void WatchConnecting()
        {
            while (true)
            {
                try
                {
                    socConnection = socketWatch.Accept();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message); //提示套接字监听异常
                    break;
                }
                //获取访问客户端的IP
                clientIP = (socConnection.RemoteEndPoint as IPEndPoint).Address;
                //获取访问客户端的Port
                clientPort = (socConnection.RemoteEndPoint as IPEndPoint).Port;
                //创建访问客户端的唯一标识 由IP和端口号组成 
                clientName = string.Format("{0}:{1}", clientIP, clientPort);

                dicSocket.Add(clientName, socConnection); //将客户端名字和套接字添加到添加到数据字典中

                //创建通信线程 
                ParameterizedThreadStart pts = new ParameterizedThreadStart(ServerRecMsg);
                Thread thread = new Thread(pts);
                thread.IsBackground = true;
                //启动线程
                thread.Start(socConnection);
                ADFS.Instance.Log.WriteLog("","[{0}:{1}] 的客户端与您连接成功,现在你们可以开始通信了.", clientIP, clientPort);
            }
        }

        /// <summary>
        /// 接收客户端发来的信息
        /// </summary>
        /// <param name="socketClientPara">客户端套接字对象</param>
        private void ServerRecMsg(object socketClientPara)
        {
            Socket socketClient = socketClientPara as Socket;
            while (true)
            {
                int length = 0;
                //创建一个接收用的内存缓冲区 大小为10M字节数组
                byte[] arrServerRecMsg = new byte[10 * 1024 * 1024];
                try
                {
                    //获取接收的数据,并存入内存缓冲区  返回一个字节数组的长度
                    length = socketClient.Receive(arrServerRecMsg);
                }
                catch (SocketException ex)
                {
                    ADFS.Instance.Log.WriteLog("","套接字异常消息:{1}", ex.Message);
                    //如果套接字出现异常 很可能是对方客户端已经断开连接
                    ADFS.Instance.Log.WriteLog("","[{0}:{1}] 已经与您断开连接", clientIP, clientPort);
                    dicSocket.Remove(clientName);//移除相应远程客户端的套接字 
                    break;
                }
                catch (Exception ex)
                {
                    ADFS.Instance.Log.WriteLog("","系统异常消息: {0}", ex.Message);
                    break;
                }
                //判断发送过来的数据是文件还是普通文字信息
                if (arrServerRecMsg[0] == 0) //0为文字信息
                {
                    //将字节数组 转换为人可以读懂的字符串
                    strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 1, length - 1);//真实有用的文本信息要比接收到的少1(标识符)
                    // 传输文件
                    if (strSRecMsg.StartsWith("soimc-file-send:"))
                    {
                        strSRecMsg = strSRecMsg.Substring(11);
                    }

                    //将接收到的信息附加到文本框txtMsg上
                    if(MessageReceivedHandler!=null) MessageReceivedHandler(string.Format("[{1}:{2}] {0} {4}{3}{4}", DateTime.Now, clientIP, clientPort, strSRecMsg, Environment.NewLine),clientIP.ToString(),clientPort);
                }
                //如果发送过来的数据是文件
                if (arrServerRecMsg[0] == 1)
                {
                    //调用接受文件的方法
                    //SaveFile(arrServerRecMsg, length - 1);//同样实际文件长度需要-1(减去标识符)
                }
            }
        }
    }
}
